// ===============================================================================
// scan: sequential scan of a large descriptor collection
// Created in September 2007 as a project for an Advanced Database Systems course
// (c) Reykjavik University, Björn Þór Jónsson, Kristleifur Daðason, Herwig Lejsek
// Contact author: Björn Þór Jónsson, Reykjavík University, bjorn@ru.is
// ===============================================================================

#include "SequentialScan.h"
#include "LLNode.h"

QueryDescInfo **Scan(DescMapper *qdescs, ConfigMapper *cnfg, IndexMapper *indx, int nns)
{
	// Create a query data structure for each descriptor
	QueryDescInfo **qinfos = new QueryDescInfo *[qdescs->getNumDescs()];
	qdescs->open();
	for (int i=0; i<qdescs->getNumDescs(); i++)
		qinfos[i] = new QueryDescInfo(qdescs->next(), cnfg->getNumDims(), nns);
	qdescs->close();

	// Then scan all clusters, then all descs in cluster, and
	// compare to all query descriptors
	int count = 0;
	
	
	for (int cl=0; cl<indx->getNumClusters(); cl++) {
		// Get the cluster
		ClusterMapper *cluster = indx->getCluster(cl);
		/* * /
		FlexDescriptor *cp = indx->getCentroid(cl);
		for(int x = 0; x < cnfg->getNumDims(); x++){
			cout << (int)cp->dim[x] << " ";
		}
		cout << endl;
		//*/
		// Open a scan of the cluster and loop through all descriptors
		cluster->open();
		FlexDescriptor *desc;
		while ((desc = cluster->next()) != NULL) {
			// Have a descriptor, so compare to all query descriptors
			for (int i=0; i<qdescs->getNumDescs(); i++) 
				qinfos[i]->compareAndReplaceFarthest(desc);
		}

		// Clean up after the scan
		cluster->close();
		delete cluster;
	}

	return qinfos;
};

QueryDescInfo **CScan(DescMapper *qdescs, ConfigMapper *cnfg, IndexMapper *indx, int nns, int clusterstosearch){
	
	// Container for the results.
	QueryDescInfo **qinfos = new QueryDescInfo *[qdescs->getNumDescs()];
	// Container for the clusters closest to the given point.
	QueryDescInfo **qclust = new QueryDescInfo *[qdescs->getNumDescs()];
	qdescs->open();
	for (int i=0; i<qdescs->getNumDescs(); i++) 
	{
		FlexDescriptor* next = qdescs->next();
		qinfos[i] = new QueryDescInfo(next, cnfg->getNumDims(), nns);
		qclust[i] = new QueryDescInfo(next, cnfg->getNumDims(), clusterstosearch);
		for (int y= 0; y<indx->getNumClusters(); y++) {
			FlexDescriptor* cent = indx->getCentroid(y);
			qclust[i]->compareAndReplaceFarthest(cent);
		}
	}
	qdescs->close();

	// Create a linke list structure for all the requested clusters.
	// init the link list structure.
	LLNode** clusterList = new LLNode* [indx->getNumClusters()];
	for (int x=0; x < indx->getNumClusters(); x++) {
		clusterList[x] = new LLNode(-1);
	}
	// put the query ids into the linke list structure for the Clusters.
	for (int i=0; i < qdescs->getNumDescs(); i++) {
		qclust[i]->open();
		int* cl;
		while ( (cl = qclust[i]->next()) != NULL) {
			clusterList[*cl] = new LLNode(i,clusterList[*cl]);
		}
	}
	int smu = 0;
	// Now we can loop through the clusters, and use the link list structure to 
	// know whiche query point wants to scan it's points.
	for (int c= 0; c<indx->getNumClusters(); c++) {
		if ( clusterList[c]->next != NULL) {
			ClusterMapper* cl = indx->getCluster(c);
			cl->open();
			FlexDescriptor* p = cl->next();
			while (p != NULL) {
				LLNode* nxt = clusterList[c];
				while ( nxt->queryid != -1) {
					qinfos[nxt->queryid]->compareAndReplaceFarthest(p);
					nxt = nxt->next;
				}
				p = cl->next();
			}
			cl->close();
		}
		else {
			smu++;
		}
	}
	cout << smu << " clusters skiped of "<< indx->getNumClusters() <<endl;
	// Clean up the cluster link list structure.
	for (int i=0; i<indx->getNumClusters(); i++) {
		delete clusterList[i];	
	}
	delete clusterList;
	// Clean up the cluster neighbourhood.
	for (int i= 0; i<qdescs->getNumDescs(); i++) {
		delete qclust[i];
	}
	delete qclust;
	return qinfos;
}